package com.blen.videolib.edit;

import android.animation.ValueAnimator;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;

import com.blen.videolib.VideoSDK;
import com.blen.videolibs.R;
import com.blen.videolib.util.FFUtils;
import com.blen.videolib.util.StringUtils;

import icangyu.base.BaseActivity;
import icangyu.base.utils.LogUtils;

import java.io.File;
import java.lang.ref.WeakReference;


/**
 * ================================================
 * 作    者：顾修忠-guxiuzhong@youku.com/gfj19900401@163.com
 * 版    本：
 * 创建日期：2017/4/8-下午3:48
 * 描    述：
 * 修订历史：
 * ================================================
 */
public class VideoCutTimeActivity extends BaseActivity implements DialogInterface.OnCancelListener {
    private static final String TAG = VideoCutTimeActivity.class.getSimpleName();
    private static final long MIN_CUT_DURATION = VideoSDK.VIDEO_MIN_LENGTH;// 最小剪辑时间3s
    private static final long MAX_CUT_DURATION = VideoSDK.VIDEO_MAX_LENGTH;//视频最多剪切多长时间
    private static final int MAX_COUNT_RANGE = 10;//seekBar的区域内一共有多少张图片
    private LinearLayout seekBarLayout;
    private ExtractVideoInfoUtil mExtractVideoInfoUtil;
    private int mMaxWidth;

    private long duration;
    private RangeSeekBar seekBar;
    private VideoView mVideoView;
    private RecyclerView mRecyclerView;
    private ImageView positionIcon;
    private VideoCutTimeAdapter videoEditAdapter;
    private float averageMsPx;//每毫秒所占的px
    private float averagePxMs;//每px所占用的ms毫秒
    private String OutPutFileDirPath;
    private ExtractFrameWorkThread mExtractFrameWorkThread;
    private String path;
    private long leftProgress, rightProgress;
    private long scrollPos = 0;
    private int mScaledTouchSlop;
    private int lastScrollX;
    private boolean isSeeking;
    private TextView tvCancel,tvConfirm;
    private int thumbnailsCount;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_video_cut_time);
        initData();
        initView();
        initEditVideo();
        initPlay();
    }

    private void initData() {
        path = getIntent().getStringExtra("path");//Environment.getExternalStorageDirectory() + "/2.mp4";
        //for video check
        if (!new File(path).exists()) {
            Toast.makeText(this, "视频文件不存在", Toast.LENGTH_LONG).show();
            finish();
        }
        mExtractVideoInfoUtil = new ExtractVideoInfoUtil(path);
        duration = Long.valueOf(mExtractVideoInfoUtil.getVideoLength());


        mMaxWidth = UIUtil.getScreenWidth(this) - UIUtil.dip2px(this, 70);
        mScaledTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
    }

    private void initView() {
        tvCancel = findViewById(R.id.tvCancel);
        tvCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
        tvConfirm = findViewById(R.id.tvConfirm);
        tvConfirm.setOnClickListener(v -> {
            //完成剪切, 返回地址
            //是否剪切过?
            if(leftProgress <1 && rightProgress == duration){
                onBackPressed();
            }else if(thumbnailsCount<=videoEditAdapter.getItemCount()){//加载完成才行
                cutVideo();
            }
        });
        tvConfirm.setClickable(false);
        tvConfirm.setTextColor(0x5f3BAF20);
        seekBarLayout = findViewById(R.id.id_seekBarLayout);
        mVideoView = findViewById(R.id.uVideoView);
        positionIcon = findViewById(R.id.positionIcon);
        mRecyclerView = findViewById(R.id.id_rv_id);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        videoEditAdapter = new VideoCutTimeAdapter(this,
                (UIUtil.getScreenWidth(this) - UIUtil.dip2px(this, 70)) / 10);
        mRecyclerView.setAdapter(videoEditAdapter);
        mRecyclerView.addOnScrollListener(mOnScrollListener);
    }


    private void initEditVideo() {
        //for video edit
        long startPosition = 0;
        long endPosition = duration;
        int rangeWidth;
        boolean isOverCeil;
        if (endPosition <= MAX_CUT_DURATION) {
            isOverCeil = false;
            thumbnailsCount = MAX_COUNT_RANGE;
            rangeWidth = mMaxWidth;
        } else {
            isOverCeil = true;
            thumbnailsCount = (int) (endPosition * 1.0f / (MAX_CUT_DURATION * 1.0f) * MAX_COUNT_RANGE);
            rangeWidth = mMaxWidth / MAX_COUNT_RANGE * thumbnailsCount;
        }
        mRecyclerView.addItemDecoration(new EditSpacingItemDecoration(UIUtil.dip2px(this, 35), thumbnailsCount));

        //init seekBar
        if (isOverCeil) {
            seekBar = new RangeSeekBar(this, 0L, MAX_CUT_DURATION);
            seekBar.setSelectedMinValue(0L);
            seekBar.setSelectedMaxValue(MAX_CUT_DURATION);
        } else {
            seekBar = new RangeSeekBar(this, 0L, endPosition);
            seekBar.setSelectedMinValue(0L);
            seekBar.setSelectedMaxValue(endPosition);
        }
        seekBar.setMin_cut_time(MIN_CUT_DURATION);//设置最小裁剪时间
        seekBar.setNotifyWhileDragging(true);
        seekBar.setOnRangeSeekBarChangeListener(mOnRangeSeekBarChangeListener);
        seekBarLayout.addView(seekBar);

        LogUtils.d(TAG, "-------thumbnailsCount--->>>>" + thumbnailsCount);
        averageMsPx = duration * 1.0f / rangeWidth * 1.0f;
        LogUtils.d(TAG, "-------rangeWidth--->>>>" + rangeWidth);
        LogUtils.d(TAG, "-------localMedia.getDuration()--->>>>" + duration);
        LogUtils.d(TAG, "-------averageMsPx--->>>>" + averageMsPx);
        OutPutFileDirPath = PictureUtils.getSaveEditThumbnailDir(String.valueOf(path.hashCode()));
        int extractW = (UIUtil.getScreenWidth(this) - UIUtil.dip2px(this, 70)) / MAX_COUNT_RANGE;
        //高度应该有个换算比
        int width = mExtractVideoInfoUtil.getVideoWidth();
        int height = mExtractVideoInfoUtil.getVideoHeight();
        int extractH = 0;
        if(height>0){
            extractH = height*extractW/width;//
        }else {
            extractH = UIUtil.dip2px(this, 55);
        }
        LogUtils.d("blensmile1","start:"+startPosition+"  end:"+endPosition+"  thumbCnt:"+thumbnailsCount+" duration:"+duration);
        mExtractFrameWorkThread = new ExtractFrameWorkThread(extractW, extractH, mUIHandler, path, OutPutFileDirPath, startPosition, endPosition, thumbnailsCount);
        mExtractFrameWorkThread.start();

        //init pos icon start
        leftProgress = 0;
        if (isOverCeil) {
            rightProgress = MAX_CUT_DURATION;
        } else {
            rightProgress = endPosition;
        }
        averagePxMs = (mMaxWidth * 1.0f / (rightProgress - leftProgress));
        LogUtils.d(TAG, "------averagePxMs----:>>>>>" + averagePxMs);


    }


    private void initPlay() {
        mVideoView.setVideoPath(path);
        //设置videoview的OnPrepared监听
        mVideoView.setOnPreparedListener(mp -> {
            //设置MediaPlayer的OnSeekComplete监听
            mp.setOnSeekCompleteListener(mp1 -> {
                if (!isSeeking) {
                    videoStart();
                }
            });
        });
        //first
        videoStart();
    }

    private boolean isOverScaledTouchSlop;

    private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            LogUtils.d(TAG, "-------newState:>>>>>" + newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                isSeeking = false;
//                videoStart();
            } else {
                isSeeking = true;
                if (isOverScaledTouchSlop && mVideoView != null && mVideoView.isPlaying()) {
                    videoPause();
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            isSeeking = false;
            int scrollX = getScrollXDistance();
            //达不到滑动的距离
            if (Math.abs(lastScrollX - scrollX) < mScaledTouchSlop) {
                isOverScaledTouchSlop = false;
                return;
            }
            isOverScaledTouchSlop = true;
            LogUtils.d(TAG, "-------scrollX:>>>>>" + scrollX);
            //初始状态,why ? 因为默认的时候有35dp的空白！
            if (scrollX == -UIUtil.dip2px(VideoCutTimeActivity.this, 35)) {
                scrollPos = 0;
            } else {
                // why 在这里处理一下,因为onScrollStateChanged早于onScrolled回调
                if (mVideoView != null && mVideoView.isPlaying()) {
                    videoPause();
                }
                isSeeking = true;
                scrollPos = (long) (averageMsPx * (UIUtil.dip2px(VideoCutTimeActivity.this, 35) + scrollX));
                LogUtils.d(TAG, "-------scrollPos:>>>>>" + scrollPos);
                leftProgress = seekBar.getSelectedMinValue() + scrollPos;
                rightProgress = seekBar.getSelectedMaxValue() + scrollPos;
                LogUtils.d(TAG, "-------leftProgress:>>>>>" + leftProgress);
                mVideoView.seekTo((int) leftProgress);
            }
            lastScrollX = scrollX;
        }
    };

    /**
     * 水平滑动了多少px
     *
     * @return int px
     */
    private int getScrollXDistance() {
        LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        int position = layoutManager.findFirstVisibleItemPosition();
        View firstVisibleChildView = layoutManager.findViewByPosition(position);
        int itemWidth = firstVisibleChildView.getWidth();
        return (position) * itemWidth - firstVisibleChildView.getLeft();
    }

    private ValueAnimator animator;

    private void anim() {
        LogUtils.d(TAG, "--anim--onProgressUpdate---->>>>>>>" + mVideoView.getCurrentPosition());
        if (positionIcon.getVisibility() == View.GONE) {
            positionIcon.setVisibility(View.VISIBLE);
        }
        final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) positionIcon.getLayoutParams();
        int start = (int) (UIUtil.dip2px(this, 35) + (leftProgress/*mVideoView.getCurrentPosition()*/ - scrollPos) * averagePxMs);
        int end = (int) (UIUtil.dip2px(this, 35) + (rightProgress - scrollPos) * averagePxMs);
        animator = ValueAnimator
                .ofInt(start, end)
                .setDuration((rightProgress - scrollPos) - (leftProgress/*mVideoView.getCurrentPosition()*/ - scrollPos));
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                params.leftMargin = (int) animation.getAnimatedValue();
                positionIcon.setLayoutParams(params);
            }
        });
        animator.start();
    }

    private final MainHandler mUIHandler = new MainHandler(this);
    private void addItem(VideoCutTimeInfo info){
        if(videoEditAdapter!=null) {
            videoEditAdapter.addItemVideoInfo(info);
//            LogUtils.d("blensmile1","info:"+info.path+"  time:"+info.time);
            if (videoEditAdapter.getItemCount() >= thumbnailsCount) {
                tvConfirm.setClickable(true);
                tvConfirm.setTextColor(0xff3BAF20);
            }
        }
    }

    @Override
    public void onCancel(DialogInterface dialogInterface) {
       onBackPressed();
    }

    private static class MainHandler extends Handler {
        private final WeakReference<VideoCutTimeActivity> mActivity;

        MainHandler(VideoCutTimeActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            VideoCutTimeActivity activity = mActivity.get();
            if (activity != null) {
                if (msg.what == ExtractFrameWorkThread.MSG_SAVE_SUCCESS) {
                        VideoCutTimeInfo info = (VideoCutTimeInfo) msg.obj;
                        activity.addItem(info);
                }
            }
        }
    }

    private final RangeSeekBar.OnRangeSeekBarChangeListener mOnRangeSeekBarChangeListener = new RangeSeekBar.OnRangeSeekBarChangeListener() {
        @Override
        public void onRangeSeekBarValuesChanged(RangeSeekBar bar, long minValue, long maxValue, int action, boolean isMin, RangeSeekBar.Thumb pressedThumb) {
            LogUtils.d(TAG, "-----minValue----->>>>>>" + minValue);
            LogUtils.d(TAG, "-----maxValue----->>>>>>" + maxValue);
            leftProgress = minValue + scrollPos;
            rightProgress = maxValue + scrollPos;
            LogUtils.d(TAG, "-----leftProgress----->>>>>>" + leftProgress);
            LogUtils.d(TAG, "-----rightProgress----->>>>>>" + rightProgress);
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    LogUtils.d(TAG, "-----ACTION_DOWN---->>>>>>");
                    isSeeking = false;
                    videoPause();
                    break;
                case MotionEvent.ACTION_MOVE:
                    LogUtils.d(TAG, "-----ACTION_MOVE---->>>>>>");
                    isSeeking = true;
                    mVideoView.seekTo((int) (pressedThumb == RangeSeekBar.Thumb.MIN ?
                            leftProgress : rightProgress));
                    break;
                case MotionEvent.ACTION_UP:
                    LogUtils.d(TAG, "-----ACTION_UP--leftProgress--->>>>>>" + leftProgress);
                    isSeeking = false;
                    //从minValue开始播
                    mVideoView.seekTo((int) leftProgress);
//                    videoStart();
                    break;
                default:
                    break;
            }
        }
    };


    private void videoStart() {
        LogUtils.d(TAG, "----videoStart----->>>>>>>");
        mVideoView.start();
        positionIcon.clearAnimation();
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
        anim();
        handler.removeCallbacks(run);
        handler.post(run);
    }

    private void videoProgressUpdate() {
        long currentPosition = mVideoView.getCurrentPosition();
        LogUtils.d(TAG, "----onProgressUpdate-cp---->>>>>>>" + currentPosition);
        if (currentPosition >= (rightProgress)) {
            mVideoView.seekTo((int) leftProgress);
            positionIcon.clearAnimation();
            if (animator != null && animator.isRunning()) {
                animator.cancel();
            }
            anim();
        }
    }

    private void videoPause() {
        isSeeking = false;
        if (mVideoView != null && mVideoView.isPlaying()) {
            mVideoView.pause();
            handler.removeCallbacks(run);
        }
        LogUtils.d(TAG, "----videoPause----->>>>>>>");
        if (positionIcon.getVisibility() == View.VISIBLE) {
            positionIcon.setVisibility(View.GONE);
        }
        positionIcon.clearAnimation();
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
    }


    @Override
    protected void onResume() {
        super.onResume();
        if (mVideoView != null) {
            mVideoView.seekTo((int) leftProgress);
            mVideoView.start();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mVideoView != null && mVideoView.isPlaying()) {
            videoPause();
        }
    }

    private Handler handler = new Handler();
    private Runnable run = new Runnable() {

        @Override
        public void run() {
            videoProgressUpdate();
            handler.postDelayed(run, 1000);
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (animator != null) {
            animator.cancel();
        }
        if (mVideoView != null) {
            mVideoView.stopPlayback();
        }
        if (mExtractVideoInfoUtil != null) {
            mExtractVideoInfoUtil.release();
        }
        mRecyclerView.removeOnScrollListener(mOnScrollListener);
        if (mExtractFrameWorkThread != null) {
            mExtractFrameWorkThread.stopExtract();
        }
        mUIHandler.removeCallbacksAndMessages(null);
        handler.removeCallbacksAndMessages(null);
//        if (!TextUtils.isEmpty(OutPutFileDirPath)) {
//            PictureUtils.deleteFile(new File(OutPutFileDirPath));
//        }
    }


    AsyncTask<Void, Void, String> task ;

    private void cutVideo() {

        if (task == null) {
            task = new AsyncTask<Void, Void, String>() {
                @Override
                protected void onPreExecute() {
                    showProgress("视频剪切中");
                }

                @Override
                protected String doInBackground(Void... params) {

                    //ffmpeg -ss 00:00:10 -t 15 -i input.mp4 -vcodec copy -acodec copy output.mp4
                    String output = VideoSDK.getVideoCache().append(System.currentTimeMillis()).append(".mp4").toString();
                    String startStr = String.valueOf(leftProgress/1000f);
                    LogUtils.b("leftProgress:"+leftProgress+" rightProgress:"+rightProgress);
//                String endStr = formatTime((int)(rightProgress-leftProgress));
                    String endStr = String.valueOf((int) (rightProgress - leftProgress) / 1000);

//                StringBuilder sb = new StringBuilder("ffmpeg")
//                        .append(" -i ").append(path)
//                        .append(" -ss ").append(startStr)
//                        .append(" -t ").append(endStr)
//                        .append(" -codec ")
//                        .append(" copy ")
//                        .append(output);
                    //直接把压缩加上去吧
                    //https://blog.csdn.net/happydeer/article/details/52610060
                    String[] str = {
                            "ffmpeg",
                            "-threads",
                            "4",
                            "-i",
                            path,
                            "-ss",
                            startStr,
                            "-t",
                            endStr,
                            "-c:v",
                            "libx264",
                            "-preset",
                            "ultrafast",
                            "-crf",
                            "24",
                            "-acodec",
                            "copy",
//                        "-b:a",
//                        "24k",
//                        "-r",
//                        "24",
//                        "-c",
//                        "copy",
//                        "-copyts",
//                        "-avoid_negative_ts",
//                        "1",
                            output
                    };
                    LogUtils.d("blen", StringUtils.concat(str, " "));
                    int i = FFUtils.run(str);
                    if (i == 0) {
                        return output;
                    } else {
                        return "";
                    }
                }

                @Override
                protected void onPostExecute(String result) {
                    hideProgress();
                    if(isCancelled()) {
                        task = null;
                        return;
                    }
                    if (!TextUtils.isEmpty(result)) {
                        Toast.makeText(VideoCutTimeActivity.this, "剪切成功", Toast.LENGTH_SHORT).show();
//                    CutSizeActivity.renameFile(result, path);
                        Intent intent = new Intent();
                        intent.putExtra("videoPath", result);
                        setResult(RESULT_OK, intent);
                        finish();
                    } else {
                        //剪裁失败
                        Toast.makeText(VideoCutTimeActivity.this, "裁剪失败", Toast.LENGTH_SHORT).show();
                    }
                    task = null;
                }
            };
            task.execute();
        } else{
            Toast.makeText(VideoCutTimeActivity.this, "裁剪失败", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onBackPressed() {
        if(task!=null){
            task.cancel(true);
            task = null;
            return;
        }
        super.onBackPressed();
    }

    private  String formatTime(int t){
        int time = t/1000;
        int h=0,m=0,s=0;
        if(t>60*60){
            h = time/60*60;
            time %= 60*60;
        }
        if(t>60){
            m = time/60;
            time%=60;
        }
        s = time;
        return String.format("%1$02d:%2$02d:%3$02d",h,m,s);
    }
}
